/**
  ETFAna project, Anyang Normal University && IMP-CAS
  \class ETFDCTa
  \brief for DCs around the target
  \author SUN Yazhou, asia.rabbit@163.com
  \since 2021-10-28
  \date 2023-04-16 last modified
  \attention
  changelog
  <table>
  <tr>  <th>Date         <th>Author      <th>Description                   </tr>
  <tr>  <td>2021-10-28   <td>Asia Sun    <td>file created                  </tr>
  </table>

  \copyright Copyright (c) 2021-2024 Anyang Normal U. && IMP-CAS with LGPLv3 LICENSE
*/

#include <iostream>
#include <cstring>
#include <TClonesArray.h>
#include <TGraph.h>
#include <TTree.h>
#include "ETFRun.h"
#include "ETFDCHit.h"
#include "ETFMath.h"
#include "ETFMsg.h"
#include "ETFDCTa.h"

using std::cout;
using std::endl;

ETFDCTa::ETFDCTa(const char *name) : ETFVDC(name){
  const char xy[] = {'X', 'Y'};
  for(int i = 0; i < 2; i++) for(int j = 0; j < 2; j++){
    fHits[i][j] = new TClonesArray("ETFDCHit");
    char name_cl[128]; sprintf(name_cl, "%s%c%d", name, xy[i], j);
    fHits[i][j]->SetName(name_cl);
  } // end embedded for
} // end ctor

ETFDCTa::~ETFDCTa(){
  for(auto &h : fHits) for(auto &l : h) if(l) delete l;
} // end the dtor

void ETFDCTa::Register(){
  for(auto &p : fHits) for(auto &l : p) if(l) fTree->Branch(l->GetName(), &l);
  string b = fName + "_wireHitPos";
  fTree->Branch(b.data(), fWireHitPos, (b+"[2]/D").data());
} // end member function Register

TClonesArray *ETFDCTa::GetHitsArray(DCType typeDC, int x12){
  if(x12 < 0 || x12 >= 2) ETFMsg::Error("ETFDC", "GetHitsArray: x12 out of range");
  if(DCType::kV == typeDC) ETFMsg::Error("ETFDC", "GetHitsArray: typeDC out of range");
  return fHits[short(typeDC)%2][x12%2];
} // end member function GetHitsArray

// initialize the detector
void ETFDCTa::Initialize(){
  ETFDetector::Initialize();
  for(auto &h : fHits) for(auto &l : h) if(l) l->Clear();
  fWireHitPos[0] = fWireHitPos[1] = -999.;
} // end member function Initialize

// identify the hit, and assign its identity to itself, and register in the det
void ETFDCTa::AddHit(const ETFRawChannel *ch, int wireId, DCType typeDC){
  static const char *cc = "xy"; // // = 'x' or 'y' according to typeDC
  const int x12 = wireId / fNL, id = wireId % fNL;
  const int xy = int(typeDC);
  ETFDCHit *hit =
    static_cast<ETFDCHit *>(fHits[xy][x12]->ConstructedAt(fHits[xy][x12]->GetEntriesFast()));
  hit->Initialize();
  hit->SetTChannel(ch);
  hit->SetLayerId(fDCId*2 + x12); // 0-1-2-3-4-5: DC0X1-X2--DC1X1-X2--DC2X1-X2
  hit->SetWireId(id);
  hit->SetDelay(fDelay);
  // set position in local frame
  if(DCType::kX == typeDC){ // X
    hit->SetX(fX0Min + fSenseWireDistance*id + fStagger12*x12);
    hit->SetY(0.);
    hit->SetZ(fLayerSpace12*x12);
  } // end if
  if(DCType::kY == typeDC){ // Y
    hit->SetX(0.);
    const double y = fY0Min + fSenseWireDistance*id + fStaggerY12*x12;
    hit->SetY(y);
    hit->SetZ(fLayerSpace12*x12 + fLayerSpaceXY);
  } // end if
  hit->SetName(ETFMsg::Form("%s_%c%d_id%d", GetName(), cc[xy], x12 + 1, id));

  TransformToLabRef(hit);
  SetHitProjection(hit, typeDC);
} // end member function AddHit

void ETFDCTa::DrawHits(){
  for(auto &h : fHits[0]) if(h) for(const auto &p : *h)
    dynamic_cast<ETFDCHit *>(p)->Draw();
} // end member function DrawHits

// set projection of the wire center position to the wire's normal plane
void ETFDCTa::SetHitProjection(ETFDCHit *hit, DCType typeDC){
  if(DCType::kX == typeDC) hit->SetProjection(hit->GetPosition()); // use as it is
  if(DCType::kY == typeDC){
    // projection of the wire center position to the wire's normal plane
    // the Y value would be used in place of X here
    double proj[3] = {hit->GetY(), hit->GetX(), hit->GetZ()};
    hit->SetProjection(proj);
  } // end if
} // end member function SetHitProjection

void ETFDCTa::Print(){
  if(!fIsFired) return;
  ETFDetector::Print();
  static const char *dcType[] = {"DCType::kX", "DCType::kY"};
  static const char *x12[] = {"1", "2"};
  static const char *xy[] = {"X", "Y"};
  int i = 0, j = 0;
  cout << "Number of sense wires per layer: " << fNL << endl;
  for(auto &h : fHits){
    cout << "\033[33;1m___________DCType: " << dcType[i] << "___________\033[0m" << endl;
    j = 0;
    for(auto &l : h){
      cout << "\033[31;1m-------------- " << xy[i] << x12[j] << " --------------\033[0m" << endl;
      for(auto p : *l) dynamic_cast<ETFDCHit *>(p)->Print();
      j++;
    } // end for over x1-x2
    i++;
  } // end for over xy
} // end member function Print

// finish the processing of all the assigned data
void ETFDCTa::PostAssign(){
  ETFVDC::PostAssign();
  for(auto &i : fHits) for(auto &j : i) for(auto b : *j)
    dynamic_cast<ETFDCHit *>(b)->Assign();
  
  // assign hit pos (fWireHitX and fWireHitY) with only wire position
  for(int i = 0; i < 2; i++){ // loop over X and Y
    if(1 == fHits[i][0]->GetEntriesFast() && 1 == fHits[i][1]->GetEntriesFast()){
      const double x0 = dynamic_cast<ETFDCHit *>(fHits[i][0]->At(0))->GetPosition(i);
      const double x1 = dynamic_cast<ETFDCHit *>(fHits[i][1]->At(0))->GetPosition(i);
      if(fabs(x0-x1) < fMaxDL*1.1) fWireHitPos[i] = (x0 + x1) * 0.5;
    } // end if
  } // end for over x and y
} // end member function PostAssign

// filter all layers
void ETFDCTa::Filter(){
  Filter(fHits[0][0]); Filter(fHits[0][1]); // X0-1
  Filter(fHits[1][0]); Filter(fHits[1][1]); // Y0-1
} // end member function Filter
